package com.jiangds.open.check.processor;

import com.jiangds.open.annotation.CheckRule;
import com.jiangds.open.check.ElementCheck;
import com.jiangds.open.util.NumberUtil;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * {@link DefaultSingleProcessor}  默认单项流程校验器
 *
 * @author jiangliang
 * @since 2021/1/7 8:41
 */
public class DefaultSingleProcessor implements SingleProcessor{

    private static volatile DefaultSingleProcessor singleProcessor = null;

    public static SingleProcessor getInstance() {
        if(singleProcessor ==null){
            synchronized (DefaultSingleProcessor.class){
                if(singleProcessor == null){
                    return new DefaultSingleProcessor();
                }
            }
        }
        return singleProcessor;
    }

    @Override
    public void annotationCheck(Class<?> type, Object targetValue, List<CheckRule> checkRules) {
        for (CheckRule checkRule : checkRules) {
            //string
            if (type == String.class) {
                this.processorCheck(
                        ElementCheck.of((String) targetValue),
                        checkRule,
                        Double::intValue, null,
                        ProcessorType.STRING_OR_NUMBER);
            }
            // byte short integer
            else if (NumberUtil.isInteger(type)) {
                this.processorCheck(
                        ElementCheck.of(NumberUtil.toIntegerClass(targetValue)),
                        checkRule,
                        Double::intValue, null,
                        ProcessorType.STRING_OR_NUMBER);
            }
            //long
            else if (NumberUtil.isLong(type)) {
                singleProcessor.processorCheck(
                        ElementCheck.of(NumberUtil.toLongClass(targetValue)),
                        checkRule,
                        Double::longValue, null,
                        ProcessorType.STRING_OR_NUMBER);
            }
            //double
            else if (NumberUtil.isDouble(type)) {
                this.processorCheck(
                        ElementCheck.of(NumberUtil.toDoubleClass(targetValue)),
                        checkRule,
                        Double::doubleValue, null,
                        ProcessorType.STRING_OR_NUMBER);
            }
            //double
            else if (type==BigDecimal.class) {
                this.processorCheck(
                        ElementCheck.of((BigDecimal)targetValue),
                        checkRule,
                        BigDecimal::new, null,
                        ProcessorType.STRING_OR_NUMBER);
            }
            //collection
            else if (Collection.class.isAssignableFrom(type)) {
                this.processorCheck(
                        ElementCheck.of((Collection) targetValue),
                        checkRule,
                        Double::intValue, null,
                        ProcessorType.COLLECTION_OR_MAP);
            }
            //map
            else if (Map.class.isAssignableFrom(type)) {
                this.processorCheck(
                        ElementCheck.of((Map) targetValue),
                        checkRule,
                        Double::intValue, null,
                        ProcessorType.COLLECTION_OR_MAP);
            }
            //date
            else if (type == Date.class) {
                this.processorCheck(
                        ElementCheck.of((Date) targetValue),
                        checkRule,
                        Double::intValue,
                        d -> Date.from(d.atZone(ZoneId.systemDefault()).toInstant()),
                        ProcessorType.DATE);
            }
            //localDate
            else if (type == LocalDate.class && targetValue != null) {
                this.processorCheck(
                        ElementCheck.of((LocalDate) targetValue),
                        checkRule,
                        Double::intValue,
                        LocalDateTime::toLocalDate,
                        ProcessorType.DATE);
            }
            //localDateTime
            else if (type == LocalDateTime.class && targetValue != null) {
                this.processorCheck(
                        ElementCheck.of((LocalDateTime) targetValue),
                        checkRule,
                        Double::intValue,
                        t -> t,
                        ProcessorType.DATE);
            }
        }
    }
}
